<?php

/**
 * Created by PhpStorm.
 * User: s.utkin
 * Date: 27.08.14
 * Time: 12:11
 */
namespace Pinenut;

use Pinenut\Model2;
use Pinenut\Model2\Finder;

/**
 * Абстрактный класс очереди
 *
 * @package Pinenut
 */
class Queue extends Model2 {
	/**
	 * Время создания элемента
	 *
	 * @var string
	 */
	public $createTime;

	/**
	 * Время планируемой обработки элемента
	 *
	 * @var string
	 */
	public $processTime;

	/**
	 * id процесса, который заблокировал элемент
	 *
	 * @var int
	 */
	public $pid;
	
	/**
	 * Данные, хранимые в очереди
	 *
	 * @var string
	 */
	public $data;
	public static function fields() {
		return array_merge ( parent::fields (), [ 
				'createTime' => self::INT,
				'processTime' => self::INT,
				'pid' => self::INT,
				'data' => self::MIXED 
		] );
	}
	
	function indexes() {
		return array_merge ( parent::indexes (), [ 
				'createTime' => [ 
						'createTime' => Finder::ORDER_ASC 
				],
				'processTime' => [
						'processTime' => Finder::ORDER_ASC
				],
				'pid' => [ 
						'pid' => Finder::ORDER_ASC 
				] 
		]
		 );
	}
	
	/**
	 * Добавляет элемент в хвост очереди
	 *
	 * @param $data -
	 *        	элемент
	 */
	public static function enqueue($data) {
		/**
		 *
		 * @var Queue $newQueueItem
		 */
		$newQueueItem = new static ();
		$newQueueItem->createTime = microtime ( true );
		$newQueueItem->processTime = $newQueueItem->createTime;
		$newQueueItem->pid = 0;
		$newQueueItem->data = $data;
		$newQueueItem->save ();
	}
	
	/**
	 * Возвращает элементы из головы очереди
	 *
	 * @param $count -
	 *        	ограничение по количеству возвращаемых элементов
	 * @return mixed
	 */
	public static function dequeue($count = 1) {
		/**
		 * id процесса, который обращается к очереди (к очереди могут обращаются несколько процессов)
		 */
		$pid = getmypid ();
		
		// Выбираем из головы очереди незаблокированные элементы
		/**
		 *
		 * @var Queue[] $items
		 */
		$items = static::find ()
			->where ( 'pid', 0 )
			->where ( 'processTime', microtime(true), Finder::OP_LTE)
			->order ( 'processTime' )
			->limit ( $count )
			->all ();

		// Собираем их идентификаторы в массив
		$selectedIds = [ ];
		foreach ( ( array ) $items as $item ) {
			$selectedIds [] = ( string ) $item;
		}
		
		// Массово лочим выбранные элементы очереди
		$updater = static::update ();
		$updater->set ( 'pid', ( int ) $pid )
			->where ( '_id', $selectedIds )
			->where ( 'pid', 0 )
			->execute ();
		
		// Выбираем свои залоченные элементы
		$items = static::find ()
			->where ( '_id', $selectedIds )
			->where ( 'pid', ( int ) $pid )
			->all ();

		return $items;
	}
	
	/**
	 * Очищает очередь
	 */
	public static function clear() {
		static::delete ()->execute ();
	}
	
	/**
	 * Возвращает количество элементов в очереди
	 *
	 * @return int
	 */
	public static function count() {
		return static::find ()->count ();
	}
}